package com.fce.fcesystem.service.serviceImp;

import com.fce.fcesystem.controller.BaseController;
import com.fce.fcesystem.ex.*;
import com.fce.fcesystem.mapper.UserMapper;
import com.fce.fcesystem.pojo.Menu;
import com.fce.fcesystem.pojo.Role;
import com.fce.fcesystem.pojo.RoleMenu;
import com.fce.fcesystem.pojo.User;
import com.fce.fcesystem.service.IUserService;
import com.fce.fcesystem.utils.GetMD5Pwd;
import com.fce.fcesystem.utils.JsonResult;
import com.fce.fcesystem.utils.SaltUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements IUserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(IUserService.class);

    private static final String STATUS_USER_CANCEL = "S";

    @Value("${core.portAddress}")
    private String portAddress;

    @Resource
    private UserMapper userMapper;


    @Override
    public void register(User user) {
        String account = user.getAccount();
        User result = userMapper.selectUserByAccount(account);
        if (result != null) {
            throw new UsernameDuplicateException("注册用户的姓名：" + account + "，已占用！");
        }
        String salt = SaltUtil.getSalt(8);
        user.setSalt(salt);
        Md5Hash md5Hash=new Md5Hash(user.getPassword(),salt,1024);
        user.setPassword(md5Hash.toHex());
        user.setSalt(salt);
        Timestamp timestamp = new Timestamp(new Date().getTime());
        user.setRegister_time(timestamp);
        user.setStatus("有效");
        Integer row = userMapper.insertUser(user);
        if (row != 1) {
            throw new InsertException("注册中出现错误，请联系相关人员！");
        }
        if (user.getRoleId()!=null) userMapper.insertUserRole(user.getUserId(), user.getRoleId());
    }

    @Override
    public JsonResult<String[]> login(String account, String password, HttpServletRequest httpServletRequest) {
        String rightCode = (String) httpServletRequest.getSession().getAttribute("rightCode");
        String tryCode = httpServletRequest.getParameter("tryCode");
        if (!rightCode.equals(tryCode)) {
            return new JsonResult<>(BaseController.KEY_CODE_ERROR, new String[]{"验证码错误，请重新输入"});
        }

        User user = userMapper.getUserByAccount(account);
        try {
            if(user == null || STATUS_USER_CANCEL.equals(user.getStatus())) {
                throw new UserNotFoundException("用户不存在，请先完成注册");
            }
        }catch (UserNotFoundException e) {
            LOGGER.warn("该用户已注销!!!");
            return new JsonResult<>(BaseController.USER_NOT_EXIT, new String[]{"用户已注销!!!"});
        }
        String[] str = new String[6];
        str[0] = account;
        str[1] = user.getHref();
        str[2] = String.valueOf(user.getRoleId());
        str[3] = user.getRoleName();
        str[4] = String.valueOf(user.getUserId());
        str[5] = portAddress;
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(account, password));
            subject.getSession().setTimeout(60*60*1000);
            LOGGER.info("登录成功!!!");
            return new JsonResult<String[]>(BaseController.OK,str);
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            LOGGER.warn("用户错误!!!");
            return new JsonResult<>(BaseController.USER_NOT_EXIT,new String[]{"用户不存在，请先完成注册"});
        } catch (IncorrectCredentialsException e) {
            LOGGER.warn("密码错误!!!");
            return new JsonResult<>(BaseController.PASS_INCORRECT,new String[]{"密码错误!!!"});
        }
    }

    @Override
    public void updateUserPassword(Integer id, String oldPassword, String newPassword) {
        User result = userMapper.selectUserById(id);
        if (result == null){
            throw new UserNotFoundException("用户不存在");
        }
        String salt = result.getSalt();
        String oldMd5Password = GetMD5Pwd.getMd5Password(oldPassword,salt);
        if (!result.getPassword().equals(oldMd5Password)) {
            throw new PasswordNotMatchException("原密码错误");
        }
        String newMd5Password = GetMD5Pwd.getMd5Password(newPassword, salt);
        Integer row = userMapper.updateUserPasswordById(id,newMd5Password);
        if (row != 1) {
            throw new UpdateException("修改密码时出现错误，请联系相关人员");
        }
    }

    public List<User> getAdmins(String name) {
        List<User> admins = userMapper.getAdmins(name);
        return admins;
    }

    @Override
    public List<User> selectUsers(String userName) {
        return userMapper.selectUsers(userName);
    }

    @Override
    public User selectUserById(Integer userId) {
        return userMapper.selectUserById(userId);
    }

    @Override
    public User selectUserByAccount(String account) {
        return userMapper.selectUserByAccount(account);
    }

    @Override
    public void deleteUser(Integer userId) {
        Integer row = userMapper.deleteUser(userId);
        if (row != 1) {
            throw new DeleteException("删除失败，请重试");
        }
    }

    @Override
    public void deleteUserRole(Integer userId,Integer roleId) {
        userMapper.deleteUserRole(userId,roleId);
    }

    @Override
    public String updateHref(MultipartFile file, String userName) throws IOException {
        //获取文件名以及后缀名
        String fileName = file.getOriginalFilename();
        assert fileName != null;
        fileName = UUID.randomUUID().toString() + fileName.substring(fileName.lastIndexOf("."));

        String path = System.getProperty("user.dir") + "\\src\\main\\resources\\static\\img" + "/";
        System.out.println(path);
        File filePath = new File(path);
        if (!filePath.exists()) {
            filePath.mkdirs();
        }
        file.transferTo(new File(path+fileName));
        Integer row = userMapper.headUpload(fileName,userName);
        if (row != 1) {
            throw new HeadUploadException("上传失败，请重试");
        }
        return fileName;
    }

    @Override
    @Transactional
    public void updateUser(Integer userId,Integer oldRoleId,Integer newRoleId) {
        userMapper.deleteUserRole(userId,oldRoleId);
        userMapper.insertUserRole(userId,newRoleId);
    }

    @Override
    public void updateUserInfo(Integer userId, String userName, String email,String phone){
        userMapper.updateUserInfo(userId,userName,email,phone);
    }

    @Override
    public void emailLoad(String key, String userName) {
        if (!key.equals(userMapper.selectUserByAccount(userName).getEmailKey())) {
            throw new KeyException("验证码错误");
        }else {
            userMapper.emailLoad(1, userName);
        }
    }

    @Override
    public void updatePwdByKey(String userName, String email, String key, String password) {
        User user = userMapper.selectUserByAccount(userName);
        if (user == null){
            throw new UserNotFoundException("用户不存在");
        }
        if (!key.equals(user.getEmailKey())) {
            throw new KeyException("验证码错误");
        }
        String salt = user.getSalt();
        Md5Hash md5Hash=new Md5Hash(password,salt,1024);
        Integer row = userMapper.updateUserPasswordById(user.getUserId(),md5Hash.toHex());
        if (row != 1) {
            throw new UpdateException("修改密码时出现错误，请联系相关人员");
        }
    }

    @Override
    public User findRolesByAccount(String account) {
        return userMapper.findRolesByAccount(account);
    }

    @Override
    public Role findPermsByRoleId(Integer id) {
        return userMapper.findPermsByRoleId(id);
    }

    @Override
    public User checkUserByPhone(String phone) {

        return userMapper.selectUserByPhone(phone);

    }

    @Override
    public List<Menu> loadMenu(Integer roleId) {
        List<Menu> menuList = userMapper.getMenuByRoleId(roleId);
        List<Menu> parentMenuList = menuList.stream().filter(menu -> menu.getParentId().equals(0) ).collect(Collectors.toList());

        parentMenuList.forEach(menu -> {
            List<Menu> list=new ArrayList<>();
            menuList.forEach(subMenu->{
                if (menu.getId().equals(subMenu.getParentId())){
                    list.add(subMenu);
                }
            });
            menu.setSubMenu(list);
        });
       return parentMenuList;
    }

    @Override
    public List<Menu> loadChildMenu(Integer parentId,Integer roleId) {
        List<Menu> menuChildList = userMapper.getChildMenuByParentId(parentId,roleId);
        return menuChildList;
    }

    @Override
    public List<RoleMenu> getPermissionList(String roleName) {
        List<RoleMenu> permissionList = userMapper.getPermissionList(roleName);
        return permissionList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertPermission(String roleName,Integer[] menus) {
        Role roleByName = userMapper.getRoleByName(roleName);
        if (roleByName!=null) {
            throw new UsernameDuplicateException("角色名：" + roleByName + "，已存在！");
        }

        Role role = new Role();
        role.setName(roleName);
        Integer roleId = userMapper.insertRole(role);

        if (roleId != null) {
            //菜单完整性保存
            List<Menu> list=new ArrayList<>();
            for (int i = 0; i < menus.length; i++) {
                Menu menuById = userMapper.getMenuById(menus[i]);
                list.add(menuById);
            }
            for (int i = 0; i < menus.length; i++) {
                Integer exitChird=0;
                Integer exitParent=0;
                Menu menu = userMapper.getMenuById(menus[i]);
                if (menu.getParentId()== 0){
                    //是否在数组中存在子菜单
                    for (int j = 0; j < menus.length; j++) {
                        Menu menu2 = userMapper.getMenuById(menus[j]);
                        if (menus[i] == menu2.getParentId()){
                            exitChird=1;
                            break;
                        }
                    }
                }else {
                    //是否在数组中存在父菜单
                    for (int j = 0; j < menus.length; j++) {
                        Menu menu2 = userMapper.getMenuById(menus[j]);
                        if (menu.getParentId() == menus[j]){
                            exitParent=1;
                            break;
                        }
                    }
                }
                if (exitParent == 0){
                    //查出父菜单
                    Menu parentMenuByParentId = userMapper.getParentMenuByParentId(menu.getParentId());
                    if (parentMenuByParentId !=null){
                        list.add(parentMenuByParentId);
                    }
                }

                if (exitChird == 0) {
                    //查出子菜单
                    List<Menu> childMenuById = userMapper.getChildMenuById(menu.getId());
                    if (childMenuById != null && !childMenuById.isEmpty()){
                        list.addAll(childMenuById);
                    }
                }
            }

            list.forEach(menu -> {
                userMapper.insertRoleMenu(menu.getId(),role.getId());
            });
        }
    }

    @Override
    @Transactional
    public void updatePermission(Integer roleId, String roleName,Integer[] menus) {
        //检验
        Role roleByName = userMapper.getRoleByName(roleName);
        if (roleByName!=null && !roleByName.getId().equals(roleId)) {
            throw new UsernameDuplicateException("角色名：" + roleByName.getName() + "，已存在！");
        }

        //更新角色
        Role role = new Role();
        role.setName(roleName);
        role.setId(roleId);
        userMapper.updateRole(role);
        userMapper.deleteRoleMenu(null,roleId);

        //菜单完整性保存
        List<Menu> list=new ArrayList<>();
        for (int i = 0; i < menus.length; i++) {
            Menu menuById = userMapper.getMenuById(menus[i]);
            list.add(menuById);
        }
        for (int i = 0; i < menus.length; i++) {
            Integer exitChird=0;
            Integer exitParent=0;
            Menu menu = userMapper.getMenuById(menus[i]);
            if (menu.getParentId()== 0){
                //是否在数组中存在子菜单
                for (int j = 0; j < menus.length; j++) {
                    Menu menu2 = userMapper.getMenuById(menus[j]);
                    if (menus[i] == menu2.getParentId()){
                        exitChird=1;
                        break;
                    }
                }
            }else {
                //是否在数组中存在父菜单
                for (int j = 0; j < menus.length; j++) {
                    Menu menu2 = userMapper.getMenuById(menus[j]);
                    if (menu.getParentId() == menus[j]){
                        exitParent=1;
                        break;
                    }
                }
            }
            if (exitParent == 0){
                //查出父菜单
                Menu parentMenuByParentId = userMapper.getParentMenuByParentId(menu.getParentId());
                if (parentMenuByParentId !=null){
                    list.add(parentMenuByParentId);
                }
            }

            if (exitChird == 0) {
                //查出子菜单
                List<Menu> childMenuById = userMapper.getChildMenuById(menu.getId());
                if (childMenuById != null && !childMenuById.isEmpty()){
                    list.addAll(childMenuById);
                }
            }
        }

        list.forEach(menu -> {
            userMapper.insertRoleMenu(menu.getId(),roleId);
        });
    }

    @Override
    @Transactional
    public void deletePermission(Integer roleId) {
        userMapper.deleteRole(roleId);
        userMapper.deleteRoleMenu(null,roleId);
    }

    @Override
    public List<Role> getAllRoles() {
        return userMapper.getAllRoles();
    }

    @Override
    public List<Menu> getAllMenus() {
        return userMapper.getAllMenus();
    }

}

